package com.cysyz.web.modules.base.permission.service;


import com.cysyz.mylib.dao.Conds;
import com.cysyz.mylib.dao.type.Type;
import com.cysyz.mylib.utils.MyStringUtils;
import com.cysyz.mylib.utils.myassert.MyAssert;
import com.cysyz.mylib.utils.tree.TreeBuilder;
import com.cysyz.mylib.utils.xsvmaker.XsvMaker;
import com.cysyz.mylib.utils.xsvmaker.impl.XsvMakerImpl;
import com.cysyz.web.modules.base.permission.annotation.Module;
import com.cysyz.web.modules.base.permission.annotation.ModuleFunction;
import com.cysyz.web.modules.base.permission.domain.SysPrivilege;
import com.cysyz.web.modules.base.permission.domain.SysUserRole;
import com.cysyz.web.modules.base.permission.support.PrivilegeType;
import com.cysyz.web.modules.base.support.service.BaseService;
import com.cysyz.web.modules.base.user.domain.SysUser;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;

/**
 * Created by abroad on 2014/11/4.
 */

@Service
public class PermissionService extends BaseService {

    @Resource
    private PrivilegeInitTool privilegeInitTool;

    public void initAdminRole() {
        privilegeInitTool.initAdminRole();
    }

    public void initGroupGroup() {
        privilegeInitTool.initGroupGroup();
    }

    public void initAdminUser() {
        privilegeInitTool.initAdminUser();
    }

    @Resource
    private TreeBuilder treeBuilder;

    /**
     * 判断当前用户是否拥有权限
     * @param user
     * @param actionMethod
     * @return
     */
    public boolean hasPermission(SysUser user, Method actionMethod) {
        Class<?> classOfMethod = actionMethod.getDeclaringClass();
        if (!classOfMethod.isAnnotationPresent(Module.class)) {
            throw new IllegalArgumentException("the class must has @Module:" + classOfMethod);
        }
        if (!actionMethod.isAnnotationPresent(ModuleFunction.class)) {
            throw new IllegalArgumentException("the method must has @ModuleFunction:" + actionMethod);
        }

        String module = classOfMethod.getAnnotation(Module.class).code();
        String moduleFunction = actionMethod.getName();

        boolean retVal = hasPermission(user, module, moduleFunction);

        return retVal;
    }

    public boolean hasPermission(SysUser user, String module, String moduleFunction) {
        boolean retVal = false;
        XsvMaker codeInputBuilder = new XsvMakerImpl("-");
        codeInputBuilder.append(module).append(moduleFunction);

        String privilegeCodeInput = codeInputBuilder.getResult();

        SysUser sysUser = get(SysUser.class, user.getId());

        if (sysUser != null) {
            for (SysUserRole sysUserRole: sysUser.getSysUserRoles()) {
                String privilegesOfRole = sysUserRole.getSysRole().getPrivileges();
                if (MyStringUtils.hasText(privilegesOfRole) && privilegesOfRole.contains(privilegeCodeInput)) {
                    retVal = true;
                    break;
                }
            }
        }
        return retVal;
    }

    public void addNewMenuGroupGroup (SysPrivilege sysPrivilege) {
        sysPrivilege.setType(PrivilegeType.PRIVILEGE_GROUP_GROUP);
        sysPrivilege.setSysPrivilege(null);
        this.save(sysPrivilege);
    }

    public void editMenuGroupGroup(SysPrivilege sysPrivilege) {
        this.merge(SysPrivilege.class, sysPrivilege);
    }

    public void mapingMenuGroup2GroupGroup(Long groupgroupId, List<Long> menuGroupIds) {
        SysPrivilege grouggroup = this.get(SysPrivilege.class, groupgroupId);

        Conds conds = new Conds("sysPrivilege");
        conds.addFilterByDefaultTableName("id", "in", menuGroupIds);
        List<SysPrivilege> menuGroupList = this.list(SysPrivilege.class, conds);

        if (menuGroupList != null) {
            for (SysPrivilege sysPrivilege : menuGroupList) {
                sysPrivilege.setSysPrivilege(grouggroup);
            }
        }
    }

    public List<SysPrivilege> findAllMenuOfUser(Serializable userId) {
        MyAssert.notNull(userId);
        List<SysPrivilege> result = new ArrayList<SysPrivilege>();

        SysUser sysUser = this.get(SysUser.class, userId);
        if (sysUser != null) {
            Set<SysUserRole> sysUserRoleses = sysUser.getSysUserRoles();

            List<SysPrivilege> allMenuOfUser = new ArrayList<SysPrivilege>();

            for (SysUserRole sysUserRolese : sysUserRoleses) {
                allMenuOfUser.addAll(getAllPrivilegeOfRole(sysUserRolese.getSysRole().getId(), true));
            }

            result = treeBuilder.generateMultiWayTree(SysPrivilege.class, allMenuOfUser);
        }

        return result;
    }

    /**
     * 分配权限时以角色为单位。
     * 查询系统中的所有权限，并对当前角色已经拥有的权限进行标识。
     * @param roleId 用户ID
     * @return 权限集合
     */
    public List<SysPrivilege> findAllPrivilege(Serializable roleId) {
        MyAssert.notNull(roleId);
        List<SysPrivilege> result = new ArrayList<SysPrivilege>();

        Set<SysPrivilege> allPrivilege = new LinkedHashSet<SysPrivilege>();

        allPrivilege.addAll(this.list(SysPrivilege.class));

        //当前角色的权限信息
        Set<SysPrivilege> allPrivielgesOfRole = new HashSet<SysPrivilege>();

        allPrivielgesOfRole.addAll(getAllPrivilegeOfRole(roleId, false));

        if (!allPrivilege.isEmpty()) {
            for (SysPrivilege sysPrivilege : allPrivilege) {
                /*标识所有权限中角色已经拥有的权限*/
                if (allPrivielgesOfRole.contains(sysPrivilege)) {
                    sysPrivilege.setRoleHasThisPrivilege(true);
                }
            }

            result = treeBuilder.generateMultiWayTree(SysPrivilege.class, allPrivilege);
        }

        if (result != null) {
            List<SysPrivilege> hasNoGroupGroupPrivilegeGroup = new ArrayList<SysPrivilege>();
            SysPrivilege othersGroupGroup = new SysPrivilege();
            othersGroupGroup.setId(Long.MAX_VALUE);
            othersGroupGroup.setName("其他");
            othersGroupGroup.setType(PrivilegeType.PRIVILEGE_GROUP_GROUP);

            for (SysPrivilege sysPrivilege : result) {
                if (sysPrivilege.getType() != PrivilegeType.PRIVILEGE_GROUP_GROUP || sysPrivilege.getSysPrivilege() != null) {
                    sysPrivilege.setSysPrivilege(othersGroupGroup);
                    othersGroupGroup.addChild(sysPrivilege);
                    hasNoGroupGroupPrivilegeGroup.add(sysPrivilege);
                    //throw new IllegalStateException("菜单组的组的类型必须为PrivilegeType.PRIVILEGE_GROUP_GROUP，同时其sysPrivilege属性必须为null");
                }
            }

            if (!hasNoGroupGroupPrivilegeGroup.isEmpty()) {
                result.removeAll(hasNoGroupGroupPrivilegeGroup);
                result.add(othersGroupGroup);
            }
        }

        return result;
    }

    private List<SysPrivilege> getAllPrivilegeOfRole(Serializable id, Boolean getMenuOnly) {
        MyAssert.notNull(id);

        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append(" SELECT sp.id, sp.name, sp.url, sp.code, sp.parent_id parentId, icon_path as iconPath, sp.show_status as showStatusInt");
        sqlBuilder.append(" FROM FNM_SYS_SYSROLE_PRIVILEGE ssp, FNM_SYS_PRIVILEGE sp, FNM_SYS_ROLE sr");
        sqlBuilder.append(" WHERE ssp.privilege_id = sp.id AND sr.id = ssp.role_id");
        sqlBuilder.append(" AND sr.id=?");

        if (getMenuOnly) {
            //sqlBuilder.append(" AND sp.SHOW_STATUS = 0");
            sqlBuilder.append(" AND sp.type in (");
            sqlBuilder.append(MyStringUtils.listToCsv(PrivilegeType.notNormalTypes()));
            sqlBuilder.append(" )");
        }

        List<Object> params = new ArrayList<Object>();
        params.add(id);

        Map<String, Type> scalars = new HashMap<String, Type>();
        scalars.put("id", Type.LONG);
        scalars.put("name", Type.STRING);
        scalars.put("url", Type.STRING);
        scalars.put("iconPath", Type.STRING);
        scalars.put("parentId", Type.LONG);
        scalars.put("code", Type.STRING);
        scalars.put("showStatusInt", Type.INTEGER);
        return list(sqlBuilder.toString(), params, SysPrivilege.class, scalars);
    }


    public void initPrivilege(String... scanPackages) {
        privilegeInitTool.initPrivilege(scanPackages);
    }
}
